grammar diff;

options { language = CSharp2; }
@namespace {DiffParser.impl}
@members
{
	private DiffProcessor proc;
	private String fileName, newFileName, oldFileName;
	private Range curRange, oldRange, newRange;
	public diffParser(ITokenStream input, DiffProcessor processor) : this(input) { proc = processor; }
}

diff		: (file|prop)*;
file		: (INDEX SPACE path {fileName = $path.text;} CRLF SEPARATOR CRLF)
		  ((file_header hunk+) | cannot_display);
		  
prop		: CRLF PROP_CH SPACE path CRLF PROP_SEP CRLF ((nonindex anytoken*)CRLF)* CRLF+;
hunk		: hunk_header line+ {proc.HunkEndHandler();};

line		: (context_line | added_line | removed_line | no_newline) CRLF;
context_line	: SPACE line_content {proc.ContextLineHandler($line_content.text);};
added_line	: PLUS line_content {proc.AddedLineHandler($line_content.text);};
removed_line	: MINUS line_content {proc.DeletedLineHandler($line_content.text);};
no_newline 	: NNL;

line_content	: anytoken*;

hunk_header	: ATS SPACE MINUS range {oldRange=curRange;} SPACE PLUS range {newRange=curRange;} SPACE ATS CRLF
			{proc.HunkStartHandler(oldFileName, oldRange, newFileName, newRange);};
range		: b=number COMMA e=number 
			{curRange=new Range(){StartLine=ulong.Parse($b.text), EndLine=ulong.Parse($e.text)};};

cannot_display	: CD CRLF line_content /* svn:mime-type may be captured here */ CRLF;

file_header	: rem SPACE firstPath=path {oldFileName = $firstPath.text;} rev CRLF
		  add SPACE secondPath=path {newFileName = $secondPath.text;} rev CRLF;
add		: PLUS PLUS PLUS;
rem		: MINUS MINUS MINUS;
path		: anytoken+;
rev		: TAB(LB REVISION SPACE (DIGIT+ ) RB | LB WORKING_COPY RB );

number		: DIGIT+;

anytoken	: (NNL|CD|REVISION|WORKING_COPY|PROP_CH|SEPARATOR|PROP_SEP|INDEX|SPACE|TAB|PLUS|MINUS|ATS|COMMA|LB|RB|DIGIT|CHAR);
nonindex	: (NNL|CD|REVISION|WORKING_COPY|PROP_CH|SEPARATOR|PROP_SEP|SPACE|TAB|PLUS|MINUS|ATS|COMMA|LB|RB|DIGIT|CHAR);

NNL		: '\\ No newline at end of file';
CD		: 'Cannot display: file marked as a binary type.';
REVISION	: 'revision';
WORKING_COPY	: 'working copy';
PROP_CH		: 'Property changes on:';
SEPARATOR	: '===================================================================';
PROP_SEP	: '___________________________________________________________________';
SPACE		: ' ';
TAB		: '\t';
PLUS		: '+';
MINUS		: '-';
ATS		: '@@';
COMMA		: ',';
LB		: '(';
RB		: ')';
DIGIT		: '0'..'9';
INDEX		: 'Index:';
CRLF		: '\r' | '\n' | '\r\n';
CHAR		: ~('\r'|'\n');
